package cn.echisan.springbootjwtdemo.controller;

import cn.echisan.springbootjwtdemo.entity.JdbcUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.util.Map;
import java.util.Random;

/**
 * Created by echisan on 2018/6/23
 */
@RestController
@PreAuthorize("permitAll()")
@RequestMapping("/jwt/auth")
public class AuthController {
    public static final String LOGIN_VERIFY_CODE_SESSION_KEY = "login_check_code";

    private static final Logger LOGGER = LoggerFactory.getLogger(AuthController.class);
    @Autowired
    private PasswordEncoder bCryptPasswordEncoder;

    @PostMapping("/register")
    public JdbcUser registerUser(@RequestBody Map<String, String> registerUser) {
        JdbcUser user = new JdbcUser();
        user.setUsername(registerUser.get("username"));
        user.setPassword(bCryptPasswordEncoder.encode(registerUser.get("password")));
        user.setRole("ROLE_USER");
        return user;
    }

    /**
     * 图形验证码，四位
     * @param request
     * @param response
     */
    @GetMapping("/captcha.png")
    public void captcha(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        Font codeFont = new Font("Comic Sans MS", Font.PLAIN, 18);
        // 给定范围获得随机颜色（0<= fc < bc <=255）
        // @param fc 颜色起始值
        // @param bc 颜色最大值

        // 设置页面不缓存
        response.setContentType(MediaType.IMAGE_PNG_VALUE);
        response.setHeader(HttpHeaders.PRAGMA, "No-cache");
        response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache");
        response.setDateHeader(HttpHeaders.EXPIRES, 0);

        // 在内存中创建图象
        int width = 47;
        int height = 24;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 生成随机类
        SecureRandom random = null;

        // 获取图形上下文
        Graphics g = null;

        // 取随机产生的认证码(4位数字)
        StringBuilder sRand = new StringBuilder();

        try {
            random = new SecureRandom();

            g = image.getGraphics();

            // 设定背景色
            g.setColor(getRandColor(random, 200, 250));
            g.fillRect(0, 0, width, height);

            // 设定字体
            g.setFont(codeFont);

            // 画边框
            // g.setColor(new Color());
            // g.drawRect(0,0,width-1,height-1);

            //sRand = "";

            for (int i = 0; i < 4; i++) {
                String rand = String.valueOf(random.nextInt(10));
                sRand.append(rand);
                // 将认证码显示到图象中
                // 调用函数出来的颜色相同，可能是因为种子太接近，所以只能直接生成
                g.setColor(getRandColor(random, 20, 130));
                g.drawString(rand, 12 * i + 1, 16);
            }

            // 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
            for (int i = 0; i < 30; i++) {
                g.setColor(getRandColor(random, 160, 200));
                int x = random.nextInt(width);
                int y = random.nextInt(height);
                int xl = random.nextInt(12);
                int yl = random.nextInt(12);
                g.drawLine(x, y, x + xl, y + yl);
            }
        } finally {
            // 释放画图对象
            if (null != g) {
                g.dispose();
            }
        }
        // 将认证码存入SESSION
        session.setAttribute(LOGIN_VERIFY_CODE_SESSION_KEY, sRand.toString());
        // clear srand
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            os.flush();
            // out.clear();
            // out = pageContext.pushBody();
            // 输出图象到页面
            // 以下一句要用到jdk 1.4的javax.imageio包
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
            LOGGER.error("", e);
        } finally {
            if (null != os) {
                try {
                    os.close();
                    os = null;
                } catch (Exception e) {
                    LOGGER.error("", e);
                }
            }
            // out.close();
        }
        // 关于不同类型的比较，1000次编码的时间消耗：
        // jpeg： 14xx 348xxx
        // gif: 72xx
        // png: 50x 13xx
        // bmp: 35xx 11xx
    }

    private Color getRandColor(Random random, int fc, int bc) {
        if (fc > 255) {
            fc = 255;
        }
        if (bc > 255) {
            bc = 255;
        }
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
}
